/*
 * Copyright 2008 the Breachwalls OSS project and the Others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.breachwalls.mogen.model;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.ClassUtils;
import org.apache.commons.lang.StringUtils;

import com.breachwalls.mogen.xml.bean.ModelClass;
import com.breachwalls.mogen.xml.bean.ModelClassProperty;

/**
 * 汎用的なモデル.
 * @author todoken
 * @version $Revision: 31 $
 */
public class GenericModel implements Model {

    /**
     * モデルクラスのXML定義.
     */
    private ModelClass modelClass;

    /**
     * モデルのプロパティ.
     */
    private List<ModelProperty> modelProperties;

    /**
     * 親モデル.
     */
    private Model parent;

    /**
     * コンストラクタ.
     * @param newModelClass モデルクラスのXML定義
     */
    public GenericModel(ModelClass newModelClass) {
        this.modelClass = newModelClass;
        List<ModelProperty> list = new ArrayList<ModelProperty>();
        for (ModelClassProperty p : newModelClass.getModelClassProperties()) {
            list.add(new GenericModelProperty(p));
        }
        this.modelProperties = list;
    }

    /**
     * モデルクラスのXML定義を取得する.
     * @return モデルクラスのXML定義
     */
    protected ModelClass getModelClass() {
        return this.modelClass;
    }

    /**
     * 親モデルを取得する.
     * @return 親モデル
     */
    public Model getParent() {
        return parent;
    }

    /**
     * 親モデルを設定する.
     * @param newParent 親モデル
     */
    public void setParent(Model newParent) {
        this.parent = newParent;
    }

    /**
     * モデル自動生成モードを取得する.<br>
     * デフォルトは「上書き」モード.
     * @return モデル自動生成モード
     */
    public GenerateMode getGenerateMode() {
        GenerateMode mode = GenerateMode.OVERWRITE;
        if (StringUtils.isNotBlank(getModelClass().getMode())) {
            mode = GenerateMode.valueOf(getModelClass().getMode());
        }
        return mode;
    }

    /**
     * モデル名を取得する.
     * @return モデル名
     */
    public String getName() {
        return getModelClass().getName();
    }

    /**
     * モデルの説明文を取得する.<br>
     * 説明文がない場合はモデル名を取得する.
     * @return モデルの説明文
     */
    public String getDescription() {
        String description = getModelClass().getDescription();
        if (StringUtils.isBlank(description)) {
            description = getName();
        }
        return description;
    }

    /**
     * モデルのタイプを取得する.
     * @return モデルのタイプ
     */
    public ModelType getModelType() {
        if (StringUtils.isBlank(getModelClass().getType())) {
            if (getParent() == null) {
                // TODO Exceptionかえること
                throw new RuntimeException("[" + getName() + "] type not found.");
            }
            return getParent().getModelType();
        }
        return ModelType.valueOf(getModelClass().getType());
    }

    /**
     * 抽象クラスかどうかを取得する.
     * @return 抽象クラスかどうか
     */
    public boolean isAbstractClass() {
        return Boolean.valueOf(getModelClass().getAbstractClass()).booleanValue();
    }

    /**
     * モデルのフルクラス名を取得する.
     * @return モデルのフルクラス名
     */
    public String getClassName() {
        return getModelClass().getClazz();
    }

    /**
     * このモデルのパッケージ名を除いたクラス名を取得する.
     * @return パッケージ名を除いたクラス名
     */
    public String getShortClassName() {
        return ClassUtils.getShortClassName(getClassName());
    }

    /**
     * パッケージ名を取得する.
     * @return パッケージ名
     */
    public String getPackageName() {
        return ClassUtils.getPackageName(getClassName());
    }

    /**
     * モデルの継承元モデル名を取得する.
     * @return モデルの継承元モデル名
     */
    public String getExtendsModelName() {
        return getModelClass().getParent();
    }

    /**
     * モデルに設定されている親モデルのフルクラス名を取得する.
     * @return 親モデルのフルクラス名
     */
    public String getExtendsClassName() {
        if (getParent() != null) {
            return getParent().getClassName();
        }
        return null;
    }

    /**
     * モデルに設定されている親モデルのクラス名部分のみを取得する.
     * @return 親モデルのクラス名
     */
    public String getExtendsShortClassName() {
        return ClassUtils.getShortClassName(getExtendsClassName());
    }

    /**
     * モデルに設定されている親モデルのパッケージ名部分のみを取得する.
     * @return 親モデルのパッケージ名
     */
    public String getExtendsPackageName() {
        return ClassUtils.getPackageName(getExtendsClassName());
    }

    /**
     * プロパティ設定の一覧を取得する.
     * @return プロパティ設定の一覧
     */
    public List<ModelProperty> getModelProperties() {
        return this.modelProperties;
    }

}
